/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.services.auth;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.sun.jndi.ldap.LdapCtxFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.xptracker.domain.User;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.directory.InitialDirContext;
import java.text.MessageFormat;
import java.util.Hashtable;
import java.util.List;

/**
 * Used to perform LDAP Authentication.
 */
@Singleton
public class LdapAuthenticator implements Authenticator {
  private String host;
  private List<String> baseDns;

  /**
   * Construct an LDAP Authenticator
   *
   * @param host    The host to connect to
   * @param baseDns A series of formatted Base DNs that include a reference to the username in XPTracker's database.
   *                The username will be filled in wherever the string "{0}" is found.  The user's Full Name will be
   *                filled in wherever "{1}" is found.
   *                e.g. uid={0},ou=people will be turned into "uid=sstarkey,ou=people"
   *                cn={1},ou=people will be turned into "cn=Stephen Starkey,ou=people"
   */
  @Inject
  public LdapAuthenticator(@Named("ldap-host")String host, @Named("ldap-dn")List<String> baseDns) {
    this.host = host;
    this.baseDns = baseDns;
  }

  public boolean isAuthenticated(User user, String password) throws Exception {
    if (StringUtils.isBlank(password)) {
      return false;
    }

    for (String baseDn : baseDns) {
      String principal = MessageFormat.format(baseDn, user.getUsername(), user.getFullName());

      Hashtable env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, LdapCtxFactory.class.getName());
      env.put(Context.PROVIDER_URL, host);
      env.put(Context.SECURITY_AUTHENTICATION, "simple");
      env.put(Context.SECURITY_PRINCIPAL, principal);
      env.put(Context.SECURITY_CREDENTIALS, password);

      try {
        new InitialDirContext(env);
        return true;
      } catch (AuthenticationException e) {
        if (e.getMessage().contains("Invalid Credentials")) {
          LogFactory.getLog(getClass()).warn("Authentication failed.  Principal: " + principal);
        } else {
          throw e;
        }
      }
    }
    return false;
  }

  public boolean isPasswordManager() {
    return false;
  }
}
